package com.nxj.factory;

import com.nxj.annotation.*;
import com.nxj.utils.ParseUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class IOCAnnotationFactory {

    private final static List<String> autoWiredAlready = new ArrayList<>();

    private final static Map<String, Object> map = new HashMap<>();

    /**
     * 拆解所有的 Annotation 并完成 Autowired 装配
     */
    public static void doAnnotation(String parentClassPath) {
        if (parentClassPath == null || "".equals(parentClassPath)) throw new RuntimeException("你大爷");
        ParseUtils.getClassSet(parentClassPath).forEach(aClass -> {
            if (aClass.getAnnotation(Repository.class) != null || aClass.getAnnotation(Service.class) != null || aClass.getAnnotation(Component.class) != null) {
                try {
                    // 这边的 key 其实可以用 value 值指定
                    map.put(lowerFirst(aClass.getName().split("[.]")[aClass.getName().split("[.]").length - 1]), aClass.newInstance());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        // 在初始化的时候替换 对应的 bean 变成 代理类 行不通  这边要处理循环依赖的问题
        ParseUtils.getClassSet(parentClassPath).forEach(aClass -> {
            for (Field field : aClass.getDeclaredFields()) {
                if (field.getAnnotation(Autowired.class) != null) {
                    field.setAccessible(true);
                    try {
                        if (autoWiredAlready.contains(aClass.getName() + "." + field.getName())) continue;
                        field.set(map.get(lowerFirst(aClass.getName().split("[.]")[aClass.getName().split("[.]").length - 1])), map.get(field.getName()));
                        autoWiredAlready.add(aClass.getName() + "." + field.getName());
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        map.forEach((s, o) -> {
            if (o.getClass().getAnnotation(Transactional.class) != null) {
                if (o.getClass().getInterfaces() != null && o.getClass().getInterfaces().length > 0)
                    map.put(s, ((ProxyFactory) map.get("proxyFactory")).jdkProxy(o));
                else map.put(s, ((ProxyFactory) map.get("proxyFactory")).cgLibProxy(o));
            }
        });
    }

    public static Object getBean(String beanId) {
        return map.get(beanId);
    }

    public static String lowerFirst(String name) {
        char[] chars = name.toCharArray();
        chars[0] += 32;
        return String.valueOf(chars);
    }

}
